#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/delay.h>
#include <linux/bitrev.h>
#include <linux/mutex.h>
#include <linux/uaccess.h>
#include <linux/io.h>
#include <linux/pci.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/file.h>
#include <linux/blkdev.h>
#include <linux/poll.h>
#include <linux/cdev.h>
#include <linux/jiffies.h>
#include <linux/percpu.h>
#include <linux/uio.h>
#include <linux/idr.h>
#include <linux/bsg.h>
#include <linux/slab.h>

#include<linux/of.h>
#include<linux/of_gpio.h>
#include<linux/gpio.h>
#include <linux/spinlock.h>
#include <linux/of_irq.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/input.h>
#include<linux/platform_device.h>

#define KEY_NAME "myKey"
#define KEY_NUM 1

#define CLOSE_CMD _IO(0x02,1)
#define OPEN_CMD _IO(0x02,2)
#define MODIFY_CMD _IO(0x02,3)


struct myKey
{
    struct device_node *node;
    int key_gpio;
    struct mutex lock;
    unsigned long flag;
    spinlock_t lock_spin; 
    unsigned int interrupt_id;

    unsigned long expires; 
    struct timer_list timer;
    struct tasklet_struct tasklet;

    struct input_dev *input;
};

static  struct myKey key;


static void timer_function(unsigned long arg)
{
    if(gpio_get_value(key.key_gpio)==1)
    {
        input_report_key(key.input,KEY_0,1);
        input_sync(key.input);
    }
    else
    {
        input_report_key(key.input,KEY_0,0);
        input_sync(key.input);
    }
    
    return;
}

static void timer_in(void)
{
    key.timer.function = timer_function;
    key.expires =20;
    key.timer.expires = jiffies+msecs_to_jiffies(key.expires);
    key.timer.data = (unsigned long)&(key);
    mod_timer(&key.timer,key.timer.expires );//再用add就找个地锄吧。。
}

static void tasklet_func(unsigned long arg)
{
    timer_in();
}

//想要按键消抖，中断里触发下半部，下半部触发定时器，定时器里读取按键值
static irqreturn_t key_irq_handler(int irq, void * dev)
{
    tasklet_schedule(&key.tasklet);
    return 0;
}

static int key_probe(struct platform_device *dev)
{
    int ret = 0;

    key.input = input_allocate_device();
   
    key.input->name = KEY_NAME;
    __set_bit(EV_KEY,key.input->evbit);
    __set_bit(EV_REP,key.input->evbit);
    __set_bit(KEY_0,key.input->keybit);
   
    ret = input_register_device(key.input);
	if (ret) {
		input_free_device(key.input);
		return ret;
	}

    key.node = dev->dev.of_node;
    if(IS_ERR(key.node))
    {
        printk("not find key node!\r\n");
        goto error__;
    }
    key.key_gpio = of_get_named_gpio(key.node,"key_gpio",0);
    if(key.key_gpio<0)
    {
        printk("not find key gpio!\r\n");
        goto error__;
    }

    ret = gpio_request(key.key_gpio,KEY_NAME);
    if(ret)
    {
        printk("request gpio error!\r\n");
        goto error__;
    }

    gpio_direction_input(key.key_gpio);
    mutex_init(&key.lock);

    key.interrupt_id =  irq_of_parse_and_map(key.node,0);
    if(key.interrupt_id<0)
    {
        printk("not find interrupt id\r\n!");
        goto error_gpio_request;
    }
    ret = request_irq(key.interrupt_id, key_irq_handler, IRQF_TRIGGER_RISING|IRQF_TRIGGER_FALLING,KEY_NAME, &key);
    if(ret)
    {
        printk("request irq id is error!\r\n");
        goto error_gpio_request;
    }


    init_timer(&key.timer);

    spin_lock_init(&key.lock_spin);

    tasklet_init(&key.tasklet,tasklet_func,(unsigned long)&key);
    
    return 0;


error_gpio_request://释放到gpio_request为止申请过的所有资源
    gpio_free(key.key_gpio);
error__:
    return -1;
}
static int key_remove(struct platform_device *dev)
{
    del_timer_sync(&key.timer);
    free_irq(key.interrupt_id,&key);
    gpio_free(key.key_gpio);
    input_unregister_device(key.input);
    input_free_device(key.input);
    return 0;
}
struct of_device_id	of_match_table[]={
    {.compatible = "xiao,key"},
    {       },
};
struct platform_driver key_platform={
    .driver = {
        .name = KEY_NAME,
        .owner = THIS_MODULE,
        .of_match_table = of_match_table,
    },
    .probe = key_probe,
    .remove = key_remove,
};

static int __init myKey_init(void)
{
    return platform_driver_register(&key_platform);
}
static void __exit myKey_exit(void)
{
    platform_driver_unregister(&key_platform);
}
module_init(myKey_init);
module_exit(myKey_exit);
MODULE_ALIAS("xiao");
MODULE_LICENSE("GPL");
